/*
     raw os - Copyright (C)  Lingjun Chen(jorya_txj).

    This file is part of raw os.

    raw os is free software; you can redistribute it it under the terms of the 
    GNU General Public License as published by the Free Software Foundation; 
    either version 3 of the License, or  (at your option) any later version.

    raw os is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
    without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
    See the GNU General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program. if not, write email to jorya.txj@gmail.com
                                      ---

    A special exception to the LGPL can be applied should you wish to distribute
    a combined work that includes raw os, without being obliged to provide
    the source code for any proprietary components. See the file exception.txt
    for full details of how and when the exception can be applied.
*/


/* 	2013-1  Created by jorya_txj
  *	xxxxxx   please added here
  */


#include <raw_api.h>
#include <mm/raw_malloc.h>
#include <raw_work_queue.h>


OBJECT_WORK_QUEUE_MSG work_queue_msg[WORK_QUEUE_MSG_SIZE];
OBJECT_WORK_QUEUE_MSG *free_work_queue_msg;


static void work_queue_task(void *pa)
{
	RAW_U16 ret;
	OBJECT_WORK_QUEUE_MSG *msg_recv;
	WORK_QUEUE_STRUCT *wq;
	
	wq = pa;

	while (1) {

		ret = raw_queue_receive (&wq->queue, RAW_WAIT_FOREVER, (void **)(&msg_recv));

		if (ret != RAW_SUCCESS) {
			
			RAW_ASSERT(0);

		}

		wq->handle_work_queue_event(msg_recv->arg, msg_recv->msg);

		RAW_CPU_DISABLE();

		msg_recv->next = free_work_queue_msg;
		free_work_queue_msg = msg_recv;

		RAW_CPU_ENABLE();


	}

}


RAW_U16 work_queue_create(WORK_QUEUE_STRUCT *wq, RAW_U8 work_task_priority, RAW_U32 work_task_stack_size, RAW_U32 work_msg_size)
{
	RAW_U16 ret;
	void *msg_start;
	PORT_STACK *work_queue_task_stack;
	RAW_U32 aligned_stack;
	RAW_U32 align_mask;

	
	msg_start = raw_malloc(work_msg_size);
	work_queue_task_stack = raw_malloc(work_task_stack_size);

	align_mask = ~(sizeof(PORT_STACK) - 1);
	
	aligned_stack = ((PORT_STACK)work_queue_task_stack & align_mask) + 
					sizeof(PORT_STACK);
	
	/* align the work queue task stack to PORT_STACK*/

	work_queue_task_stack = (PORT_STACK *)aligned_stack;
	
	ret = raw_queue_create(&wq->queue, "work_queue", msg_start, work_msg_size);

	if (ret != RAW_SUCCESS) {

		return ret;
	}
	
	ret = raw_task_create(&wq->work_queue_task_obj, (RAW_U8  *)"task1", wq,
	                         work_task_priority, 0, work_queue_task_stack, 
	                         work_task_stack_size, work_queue_task, 1); 

	if (ret != RAW_SUCCESS) {

		return ret;
	}

	return RAW_SUCCESS;
}



void assign_work_queue_handler(WORK_QUEUE_STRUCT *wq, WORK_QUEUE_HANDLER handler)
{

	wq->handle_work_queue_event = handler;
	
}


RAW_U16 sche_work_queue(WORK_QUEUE_STRUCT *wq, RAW_U32 arg, void *msg)
{
	void *msg_data;

	RAW_SR_ALLOC();

	RAW_CPU_DISABLE();
	
	msg_data = (RAW_U8 *)free_work_queue_msg;

	if (free_work_queue_msg == 0) {
		
		RAW_ASSERT(0);
	}

	free_work_queue_msg->arg = arg;
	free_work_queue_msg->msg = msg;
	
	free_work_queue_msg = free_work_queue_msg->next;

	RAW_CPU_ENABLE();

	
	raw_queue_end_post(&wq->queue, msg_data);


	return RAW_SUCCESS;


}




void global_work_queue_init()
{
	OBJECT_WORK_QUEUE_MSG *p_msg1;
	OBJECT_WORK_QUEUE_MSG *p_msg2;
	RAW_U32 number;

	number = WORK_QUEUE_MSG_SIZE;
	
	raw_memset(work_queue_msg, 0, sizeof(work_queue_msg));
	
	free_work_queue_msg = work_queue_msg;
	
	/*init the free msg list*/
	p_msg1 = work_queue_msg;
	p_msg2 = work_queue_msg;
	p_msg2++;

	while (--number) { 

		p_msg1->next = p_msg2;

		p_msg1++;
		p_msg2++;
	}

	/*init  the last free msg*/ 
	p_msg1->next = 0;                      
	
}



